home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 7 / Amiga Format AFCD07 (Dec 1996, Issue 91).iso / serious / shareware / comms / non-internet / samba / source / clitar.c < prev    next >
C/C++ Source or Header  |  1996-06-26  |  33KB  |  1,442 lines

  1. /* 
  2.    Unix SMB/Netbios implementation.
  3.    Version 1.9.
  4.    Tar Extensions
  5.    Copyright (C) Ricky Poulten 1995
  6.    
  7.    This program is free software; you can redistribute it and/or modify
  8.    it under the terms of the GNU General Public License as published by
  9.    the Free Software Foundation; either version 2 of the License, or
  10.    (at your option) any later version.
  11.    
  12.    This program is distributed in the hope that it will be useful,
  13.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.    GNU General Public License for more details.
  16.    
  17.    You should have received a copy of the GNU General Public License
  18.    along with this program; if not, write to the Free Software
  19.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21.  
  22.  
  23. #include "includes.h"
  24. #include "clitar.h"
  25.  
  26. extern void setup_pkt(char *outbuf);
  27. extern BOOL reopen_connection(char *inbuf,char *outbuf);
  28. extern void do_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir);
  29.  
  30. extern BOOL recurse;
  31.  
  32. #define SEPARATORS " \t\n\r"
  33. extern int DEBUGLEVEL;
  34. extern int Client;
  35.  
  36. /* These defines are for the do_setrattr routine, to indicate
  37.  * setting and reseting of file attributes in the function call */
  38. #define ATTRSET 1
  39. #define ATTRRESET 0
  40.  
  41. #ifndef CLIENT_TIMEOUT
  42. #define CLIENT_TIMEOUT (30*1000)
  43. #endif
  44.  
  45. static char *tarbuf;
  46. static int tp, ntarf, tbufsiz;
  47. BOOL tar_inc=False;
  48. BOOL tar_reset=False;
  49.  
  50. extern file_info def_finfo;
  51. extern BOOL lowercase;
  52. extern int cnum;
  53. extern BOOL readbraw_supported;
  54. extern int max_xmit;
  55. extern pstring cur_dir;
  56. extern int get_total_time_ms;
  57. extern int get_total_size;
  58. extern int Protocol;
  59.  
  60. int blocksize=20;
  61. int tarhandle;
  62.  
  63. static void writetarheader();
  64. static void do_atar();
  65. void do_tar();
  66. void cmd_tar();
  67. static void oct_it();
  68. static void fixtarname();
  69. static int dotarbuf();
  70. static void dozerobuf();
  71. static void dotareof();
  72. static void initarbuf();
  73. static int do_setrattr();
  74.  
  75. /* begin smbrestore functions */
  76. static long readtarheader();
  77. static long unoct();
  78. static void do_tarput();
  79. static void unfixtarname();
  80. /* end smbrestore functions */
  81.  
  82. /*
  83.  * utitlity procedures to implement tar specification including buffering
  84.  */
  85.  
  86. static void writetarheader(int f,  char *aname, int size, time_t mtime,
  87.             char *amode)
  88. {
  89.   union hblock hb;
  90.   int i, chk, l;
  91.   char *jp;
  92.  
  93.   memset(hb.dummy, 0, sizeof(hb.dummy));
  94.   
  95.   l=strlen(aname);
  96.   if (l >= NAMSIZ)
  97.     {
  98.       DEBUG(0, ("tar file %s name length exceeds NAMSIZ\n", aname));
  99.     }
  100.  
  101.   /* use l + 1 to do the null too */
  102.   fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
  103.  
  104.   if (lowercase)
  105.     strlower(hb.dbuf.name);
  106.  
  107.   /* write out a "standard" tar format header */
  108.  
  109.   hb.dbuf.name[NAMSIZ-1]='\0';
  110.   strcpy(hb.dbuf.mode, amode);
  111.   oct_it(0L, 8, hb.dbuf.uid);
  112.   oct_it(0L, 8, hb.dbuf.gid);
  113.   oct_it((long) size, 13, hb.dbuf.size);
  114.   oct_it((long) mtime, 13, hb.dbuf.mtime);
  115.   memcpy(hb.dbuf.chksum, "        ", sizeof(hb.dbuf.chksum));
  116.   hb.dbuf.linkflag='0';
  117.   memset(hb.dbuf.linkname, 0, NAMSIZ);
  118.   
  119.   for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++);
  120.  
  121.   oct_it((long) chk, 8, hb.dbuf.chksum);
  122.   hb.dbuf.chksum[6] = '\0';
  123.  
  124.   (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
  125. }
  126.  
  127.  
  128. static int dotarbuf(int f, char *b, int n)
  129. {
  130.   int fail=1, writ=n;
  131.  
  132.   if (tp + n >= tbufsiz)
  133.     {
  134.       int diff;
  135.  
  136.       diff=tbufsiz-tp;
  137.       memcpy(tarbuf + tp, b, diff);
  138.       fail=fail && (1+write(f, tarbuf, tbufsiz));
  139.       n-=diff;
  140.       b+=diff;
  141.       tp=0;
  142.  
  143.       while (n >= tbufsiz)
  144.     {
  145.       fail=fail && (1 + write(f, b, tbufsiz));
  146.       n-=tbufsiz;
  147.       b+=tbufsiz;
  148.     }
  149.     }
  150.   if (n>0) {
  151.     memcpy(tarbuf+tp, b, n);
  152.     tp+=n;
  153.   }
  154.  
  155.   return(fail ? writ : 0);
  156. }
  157.  
  158. static void dozerobuf(int f, int n)
  159. {
  160.   /* short routine just to write out n zeros to buffer -
  161.    * used to round files to nearest block
  162.    * and to do tar EOFs */
  163.  
  164.   if (n+tp >= tbufsiz)
  165.     {
  166.       memset(tarbuf+tp, 0, tbufsiz-tp);
  167.       write(f, tarbuf, tbufsiz);
  168.       memset(tarbuf, 0, (tp+=n-tbufsiz));
  169.     }
  170.   else
  171.     {
  172.       memset(tarbuf+tp, 0, n);
  173.       tp+=n;
  174.     }
  175. }
  176.  
  177. static void initarbuf()
  178. {
  179.   /* initialize tar buffer */
  180.   tbufsiz=blocksize*TBLOCK;
  181.   tarbuf=malloc(tbufsiz);
  182.  
  183.   /* reset tar buffer pointer and tar file counter */
  184.   tp=0; ntarf=0;
  185. }
  186.  
  187. static void dotareof(int f)
  188. {
  189.   struct stat stbuf;
  190.   /* Two zero blocks at end of file, write out full buffer
  191.    * no matter what; well that's what the manual says */
  192.  
  193.   (void) dozerobuf(f, TBLOCK);
  194.   (void) dozerobuf(f, TBLOCK);
  195.  
  196.   if (fstat(f, &stbuf) == -1)
  197.     {
  198.       DEBUG(0, ("Couldn't stat file handle\n"));
  199.       return;
  200.     }
  201.  
  202.   if (tp > 0) write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
  203. }
  204.  
  205. static void fixtarname(char *tptr, char *fp, int l)
  206. {
  207.   /* add a '.' to start of file name, convert from ugly dos \'s in path
  208.    * to lovely unix /'s :-} */
  209.  
  210.   *tptr++='.';
  211. #ifdef KANJI
  212.   while (l > 0) {
  213.     if (is_shift_jis (*fp)) {
  214.       *tptr++ = *fp++;
  215.       *tptr++ = *fp++;
  216.       l -= 2;
  217.     } else if (is_kana (*fp)) {
  218.       *tptr++ = *fp++;
  219.       l--;
  220.     } else if (*fp == '\\') {
  221.       *tptr++ = '/';
  222.       fp++;
  223.       l--;
  224.     } else {
  225.       *tptr++ = *fp++;
  226.       l--;
  227.     }
  228.   }
  229. #else
  230.   while (l--) { *tptr=(*fp == '\\') ? '/' : *fp; tptr++; fp++; }
  231. #endif
  232. }
  233.  
  234. static void oct_it (register long value, register int ndgs, register char *p)
  235. {
  236.   /* Converts long to octal string, pads with leading zeros */
  237.  
  238.   /* skip final null, but do final space */
  239.   --ndgs;
  240.   p[--ndgs] = ' ';
  241.  
  242.   /* Loop does at least one digit */
  243.   do {
  244.       p[--ndgs] = '0' + (char) (value & 7);
  245.       value >>= 3;
  246.     }
  247.   while (ndgs > 0 && value != 0);
  248.  
  249.   /* Do leading zeros */
  250.   while (ndgs > 0)
  251.     p[--ndgs] = '0';
  252. }
  253.  
  254. /*
  255.  * general smb utility functions
  256.  */
  257.  
  258. static int do_setrattr(char *fname, int attr, int setit)
  259. {
  260.   /*
  261.    * First get the existing attribs from existing file
  262.    */
  263.   char *inbuf,*outbuf;
  264.   char *p;
  265.   pstring name;
  266.   int fattr;
  267.  
  268.   strcpy(name,fname);
  269.   strcpy(fname,"\\");
  270.   strcat(fname,name);
  271.  
  272.   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
  273.   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
  274.  
  275.   if (!inbuf || !outbuf)
  276.     {
  277.       DEBUG(0,("out of memory\n"));
  278.       return False;
  279.     }
  280.  
  281.   /* send an smb getatr message */
  282.  
  283.   memset(outbuf,0,smb_size);
  284.   set_message(outbuf,0,2 + strlen(fname),True);
  285.   CVAL(outbuf,smb_com) = SMBgetatr;
  286.   SSVAL(outbuf,smb_tid,cnum);
  287.   setup_pkt(outbuf);
  288.  
  289.   p = smb_buf(outbuf);
  290.   *p++ = 4;
  291.   strcpy(p,fname);
  292.   p += (strlen(fname)+1);
  293.   
  294.   *p++ = 4;
  295.   *p++ = 0;
  296.  
  297.   send_smb(Client,outbuf);
  298.   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
  299.  
  300.   if (CVAL(inbuf,smb_rcls) != 0)
  301.     DEBUG(5,("getatr: %s\n",smb_errstr(inbuf)));
  302.   else
  303.     {
  304.       DEBUG(5,("\nattr 0x%X  time %d  size %d\n",
  305.            (int)CVAL(inbuf,smb_vwv0),
  306.            SVAL(inbuf,smb_vwv1),
  307.            SVAL(inbuf,smb_vwv3)));
  308.     }
  309.  
  310.   fattr=CVAL(inbuf,smb_vwv0);
  311.  
  312.   /* combine found attributes with bits to be set or reset */
  313.  
  314.   attr=setit ? (fattr | attr) : (fattr & ~attr);
  315.  
  316.   /* now try and set attributes by sending smb reset message */
  317.  
  318.   /* clear out buffer and start again */
  319.   memset(outbuf,0,smb_size);
  320.   set_message(outbuf,8,4 + strlen(fname),True);
  321.   CVAL(outbuf,smb_com) = SMBsetatr;
  322.   SSVAL(outbuf,smb_tid,cnum);
  323.   setup_pkt(outbuf);
  324.  
  325.   SSVAL(outbuf,smb_vwv0,attr);
  326.  
  327.   p = smb_buf(outbuf);
  328.   *p++ = 4;      
  329.   strcpy(p,fname);
  330.   p += (strlen(fname)+1);
  331.   
  332.   *p++ = 4;
  333.   *p++ = 0;
  334.  
  335.   send_smb(Client,outbuf);
  336.   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
  337.   
  338.   if (CVAL(inbuf,smb_rcls) != 0)
  339.     {
  340.       DEBUG(0,("%s setting attributes on file %s\n",
  341.         smb_errstr(inbuf), fname));
  342.       free(inbuf);free(outbuf);
  343.       return(False);
  344.     }
  345.  
  346.   free(inbuf);free(outbuf);
  347.   return(True);
  348. }
  349.  
  350. /*
  351.  * smbclient support procedures
  352.  */
  353.  
  354. /****************************************************************************
  355.  do a tar operation on one file
  356. ***************************************************************************/
  357.  
  358. static void do_atar(char *rname,char *lname,file_info *finfo1)
  359. {
  360.   int fnum;
  361.   uint32 nread=0;
  362.   char *p;
  363.   char *inbuf,*outbuf;
  364.   file_info finfo;
  365.   BOOL close_done = False;
  366.   BOOL shallitime=True;
  367.   BOOL ignore_close_error = False;
  368.   char *dataptr=NULL;
  369.   int datalen=0;
  370.  
  371.   struct timeval tp_start;
  372.   GetTimeOfDay(&tp_start);
  373.  
  374.   if (finfo1) 
  375.     finfo = *finfo1;
  376.   else
  377.     finfo = def_finfo;
  378.  
  379.   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
  380.   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
  381.  
  382.   if (!inbuf || !outbuf)
  383.     {
  384.       DEBUG(0,("out of memory\n"));
  385.       return;
  386.     }
  387.  
  388.   memset(outbuf,0,smb_size);
  389.   set_message(outbuf,15,1 + strlen(rname),True);
  390.  
  391.   CVAL(outbuf,smb_com) = SMBopenX;
  392.   SSVAL(outbuf,smb_tid,cnum);
  393.   setup_pkt(outbuf);
  394.  
  395.   SSVAL(outbuf,smb_vwv0,0xFF);
  396.   SSVAL(outbuf,smb_vwv2,1);
  397.   SSVAL(outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
  398.   SSVAL(outbuf,smb_vwv5,aSYSTEM | aHIDDEN);
  399.   SSVAL(outbuf,smb_vwv8,1);
  400.  
  401.   p = smb_buf(outbuf);
  402.   strcpy(p,rname);
  403.   p = skip_string(p,1);
  404.  
  405.   dos_clean_name(rname);
  406.  
  407.   /* do a chained openX with a readX? */  
  408.   if (finfo.size > 0)
  409.     {
  410.       SSVAL(outbuf,smb_vwv0,SMBreadX);
  411.       SSVAL(outbuf,smb_vwv1,PTR_DIFF(p,outbuf) - 4);
  412.       memset(p,0,200);
  413.       p -= smb_wct;
  414.       SSVAL(p,smb_wct,10);
  415.       SSVAL(p,smb_vwv0,0xFF);
  416.       SSVAL(p,smb_vwv5,MIN(max_xmit-500,finfo.size));
  417.       SSVAL(p,smb_vwv9,MIN(0xFFFF,finfo.size));
  418.       smb_setlen(outbuf,smb_len(outbuf)+11*2+1);  
  419.     }
  420.   
  421.   send_smb(Client,outbuf);
  422.   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
  423.  
  424.   if (CVAL(inbuf,smb_rcls) != 0)
  425.     {
  426.       if (CVAL(inbuf,smb_rcls) == ERRSRV &&
  427.       SVAL(inbuf,smb_err) == ERRnoresource &&
  428.       reopen_connection(inbuf,outbuf))
  429.     {
  430.       do_atar(rname,lname,finfo1);
  431.       free(inbuf);free(outbuf);
  432.       return;
  433.     }
  434.  
  435.       DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),rname));
  436.       free(inbuf);free(outbuf);
  437.       return;
  438.     }
  439.  
  440.   strcpy(finfo.name,rname);
  441.   if (!finfo1)
  442.     {
  443.       finfo.mode = SVAL(inbuf,smb_vwv3);
  444.       finfo.size = IVAL(inbuf,smb_vwv4);
  445.       finfo.mtime = make_unix_date3(inbuf+smb_vwv6);
  446.       finfo.atime = finfo.ctime = finfo.mtime;
  447.     }
  448.  
  449.   DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
  450.  
  451.   fnum = SVAL(inbuf,smb_vwv2);
  452.  
  453.   if (tar_inc && !(finfo.mode & aARCH))
  454.     {
  455.       DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
  456.       shallitime=0;
  457.     }
  458.   else
  459.     {
  460.       if (SVAL(inbuf,smb_vwv0) == SMBreadX)
  461.     {
  462.       p = (inbuf+4+SVAL(inbuf,smb_vwv1)) - smb_wct;
  463.       datalen = SVAL(p,smb_vwv5);
  464.       dataptr = inbuf + 4 + SVAL(p,smb_vwv6);
  465.     }
  466.       else
  467.     {
  468.       dataptr = NULL;
  469.       datalen = 0;
  470.     }
  471.  
  472.       DEBUG(2,("getting file %s of size %d bytes as a tar file %s",
  473.            finfo.name,
  474.            finfo.size,
  475.            lname));
  476.       
  477.       /* write a tar header, don't bother with mode - just set to 100644 */
  478.       writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0");
  479.       
  480.       while (nread < finfo.size && !close_done)
  481.     {
  482.       int method = -1;
  483.       static BOOL can_chain_close=True;
  484.  
  485.       p=NULL;
  486.       
  487.       DEBUG(3,("nread=%d\n",nread));
  488.       
  489.       /* 3 possible read types. readbraw if a large block is required.
  490.          readX + close if not much left and read if neither is supported */
  491.  
  492.       /* we might have already read some data from a chained readX */
  493.       if (dataptr && datalen>0)
  494.         method=3;
  495.       
  496.       /* if we can finish now then readX+close */
  497.       if (method<0 && can_chain_close && (Protocol >= PROTOCOL_LANMAN1) && 
  498.           ((finfo.size - nread) < 
  499.            (max_xmit - (2*smb_size + 13*SIZEOFWORD + 300))))
  500.         method = 0;
  501.       
  502.       /* if we support readraw then use that */
  503.       if (method<0 && readbraw_supported)
  504.         method = 1;
  505.       
  506.       /* if we can then use readX */
  507.       if (method<0 && (Protocol >= PROTOCOL_LANMAN1))
  508.         method = 2;
  509.       
  510.       
  511.       switch (method)
  512.         {
  513.           /* use readX */
  514.         case 0:
  515.         case 2:
  516.           if (method == 0)
  517.         close_done = True;
  518.           
  519.           /* use readX + close */
  520.           memset(outbuf,0,smb_size);
  521.           set_message(outbuf,10,0,True);
  522.           CVAL(outbuf,smb_com) = SMBreadX;
  523.           SSVAL(outbuf,smb_tid,cnum);
  524.           setup_pkt(outbuf);
  525.           
  526.           if (close_done)
  527.         {
  528.           CVAL(outbuf,smb_vwv0) = SMBclose;
  529.           SSVAL(outbuf,smb_vwv1,PTR_DIFF(smb_buf(outbuf),outbuf) - 4);
  530.         }
  531.           else
  532.         CVAL(outbuf,smb_vwv0) = 0xFF;          
  533.           
  534.           
  535.           SSVAL(outbuf,smb_vwv2,fnum);
  536.           SIVAL(outbuf,smb_vwv3,nread);
  537.           SSVAL(outbuf,smb_vwv5,MIN(max_xmit-200,finfo.size - nread));
  538.           SSVAL(outbuf,smb_vwv6,0);
  539.           SIVAL(outbuf,smb_vwv7,0);
  540.           SSVAL(outbuf,smb_vwv9,MIN(0xFFFF,finfo.size-nread));
  541.           
  542.           if (close_done)
  543.         {
  544.           p = smb_buf(outbuf);
  545.           memset(p,0,9);
  546.           
  547.           CVAL(p,0) = 3;
  548.           SSVAL(p,1,fnum);
  549.           SIVALS(p,3,-1);
  550.           
  551.           /* now set the total packet length */
  552.           smb_setlen(outbuf,smb_len(outbuf)+9);
  553.         }
  554.           
  555.           send_smb(Client,outbuf);
  556.           receive_smb(Client,inbuf,CLIENT_TIMEOUT);
  557.           
  558.           if (CVAL(inbuf,smb_rcls) != 0)
  559.         {
  560.           DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf)));
  561.           break;
  562.         }
  563.           
  564.           if (close_done &&
  565.           SVAL(inbuf,smb_vwv0) != SMBclose)
  566.         {
  567.           /* NOTE: WfWg sometimes just ignores the chained
  568.              command! This seems to break the spec? */
  569.           DEBUG(3,("Rejected chained close?\n"));
  570.           close_done = False;
  571.           can_chain_close = False;
  572.           ignore_close_error = True;
  573.         }
  574.           
  575.           datalen = SVAL(inbuf,smb_vwv5);
  576.           dataptr = inbuf + 4 + SVAL(inbuf,smb_vwv6);
  577.           break;
  578.           
  579.           
  580.           /* use readbraw */
  581.         case 1:
  582.           {
  583.         static int readbraw_size = 0xFFFF;
  584.         
  585.         extern int Client;
  586.         memset(outbuf,0,smb_size);
  587.         set_message(outbuf,8,0,True);
  588.         CVAL(outbuf,smb_com) = SMBreadbraw;
  589.         SSVAL(outbuf,smb_tid,cnum);
  590.         setup_pkt(outbuf);
  591.         SSVAL(outbuf,smb_vwv0,fnum);
  592.         SIVAL(outbuf,smb_vwv1,nread);
  593.         SSVAL(outbuf,smb_vwv3,MIN(finfo.size-nread,readbraw_size));
  594.         SSVAL(outbuf,smb_vwv4,0);
  595.         SIVALS(outbuf,smb_vwv5,-1);
  596.         send_smb(Client,outbuf);
  597.         
  598.         /* Now read the raw data into the buffer and write it */      
  599.         if(read_smb_length(Client,inbuf,0) == -1) {
  600.           DEBUG(0,("Failed to read length in readbraw\n"));        
  601.           exit(1);
  602.         }
  603.         
  604.         /* Even though this is not an smb message, smb_len
  605.            returns the generic length of an smb message */
  606.         datalen = smb_len(inbuf);
  607.         
  608.         if (datalen == 0)
  609.           {
  610.             /* we got a readbraw error */
  611.             DEBUG(4,("readbraw error - reducing size\n"));
  612.             readbraw_size = (readbraw_size * 9) / 10;
  613.             
  614.             if (readbraw_size < max_xmit)
  615.               {
  616.             DEBUG(0,("disabling readbraw\n"));
  617.             readbraw_supported = False;
  618.               }
  619.  
  620.             dataptr=NULL;
  621.             continue;
  622.           }
  623.  
  624.         if(read_data(Client,inbuf,datalen) != datalen) {
  625.           DEBUG(0,("Failed to read data in readbraw\n"));
  626.           exit(1);
  627.         }
  628.         dataptr = inbuf;
  629.           }
  630.           break;
  631.  
  632.         case 3:
  633.           /* we've already read some data with a chained readX */
  634.           break;
  635.           
  636.         default:
  637.           /* use plain read */
  638.           memset(outbuf,0,smb_size);
  639.           set_message(outbuf,5,0,True);
  640.           CVAL(outbuf,smb_com) = SMBread;
  641.           SSVAL(outbuf,smb_tid,cnum);
  642.           setup_pkt(outbuf);
  643.           
  644.           SSVAL(outbuf,smb_vwv0,fnum);
  645.           SSVAL(outbuf,smb_vwv1,MIN(max_xmit-200,finfo.size - nread));
  646.           SIVAL(outbuf,smb_vwv2,nread);
  647.           SSVAL(outbuf,smb_vwv4,finfo.size - nread);
  648.           
  649.           send_smb(Client,outbuf);
  650.           receive_smb(Client,inbuf,CLIENT_TIMEOUT);
  651.           
  652.           if (CVAL(inbuf,smb_rcls) != 0)
  653.         {
  654.           DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf)));
  655.           break;
  656.         }
  657.           
  658.           datalen = SVAL(inbuf,smb_vwv0);
  659.           dataptr = smb_buf(inbuf) + 3;
  660.           break;
  661.         }
  662.       
  663.       
  664.       /* add received bits of file to buffer - dotarbuf will
  665.        * write out in 512 byte intervals */
  666.       if (dotarbuf(tarhandle,dataptr,datalen) != datalen)
  667.         {
  668.           DEBUG(0,("Error writing local file\n"));
  669.           break;
  670.         }
  671.       
  672.       nread += datalen;
  673.       if (datalen == 0) 
  674.         {
  675.           DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
  676.           break;
  677.         }
  678.  
  679.       dataptr=NULL;
  680.       datalen=0;
  681.     }
  682.       
  683.       /* round tar file to nearest block */
  684.       if (finfo.size % TBLOCK)
  685.     dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
  686.       
  687.       ntarf++;
  688.     }
  689.   
  690.   if (!close_done)
  691.     {
  692.       memset(outbuf,0,smb_size);
  693.       set_message(outbuf,3,0,True);
  694.       CVAL(outbuf,smb_com) = SMBclose;
  695.       SSVAL(outbuf,smb_tid,cnum);
  696.       setup_pkt(outbuf);
  697.       
  698.       SSVAL(outbuf,smb_vwv0,fnum);
  699.       SIVALS(outbuf,smb_vwv1,-1);
  700.       
  701.       send_smb(Client,outbuf);
  702.       receive_smb(Client,inbuf,CLIENT_TIMEOUT);
  703.       
  704.       if (!ignore_close_error && CVAL(inbuf,smb_rcls) != 0)
  705.     {
  706.       DEBUG(0,("Error %s closing remote file\n",smb_errstr(inbuf)));
  707.       free(inbuf);free(outbuf);
  708.       return;
  709.     }
  710.     }
  711.  
  712.   if (shallitime)
  713.     {
  714.       struct timeval tp_end;
  715.       int this_time;
  716.  
  717.       /* if shallitime is true then we didn't skip */
  718.       if (tar_reset) (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
  719.       
  720.       GetTimeOfDay(&tp_end);
  721.       this_time = 
  722.     (tp_end.tv_sec - tp_start.tv_sec)*1000 +
  723.       (tp_end.tv_usec - tp_start.tv_usec)/1000;
  724.       get_total_time_ms += this_time;
  725.       get_total_size += finfo.size;
  726.       
  727.       DEBUG(2,("(%g kb/s) (average %g kb/s)\n",
  728.            finfo.size / (1.024*this_time + 1.0e-4),
  729.            get_total_size / (1.024*get_total_time_ms)));
  730.     }
  731.   
  732.   free(inbuf);free(outbuf);
  733. }
  734.  
  735.  
  736.  
  737. void do_tar(file_info *finfo)
  738. {
  739.   pstring rname;
  740.  
  741.   if (strequal(finfo->name,".") || strequal(finfo->name,".."))
  742.     return;
  743.  
  744.   if (finfo->mode & aDIR)
  745.     {
  746.       pstring saved_curdir;
  747.       pstring mtar_mask;
  748.       char *inbuf,*outbuf;
  749.  
  750.       inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
  751.       outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
  752.  
  753.       if (!inbuf || !outbuf)
  754.     {
  755.       DEBUG(0,("out of memory\n"));
  756.       return;
  757.     }
  758.  
  759.       strcpy(saved_curdir,cur_dir);
  760.  
  761.       strcat(cur_dir,finfo->name);
  762.       strcat(cur_dir,"\\");
  763.  
  764.       /* write a tar directory, don't bother with mode - just set it to
  765.        * 40755 */
  766.       writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0");
  767.       strcpy(mtar_mask,cur_dir);
  768.       strcat(mtar_mask,"*.*");
  769.       
  770.       do_dir((char *)inbuf,(char *)outbuf,
  771.          mtar_mask,aSYSTEM | aHIDDEN | aDIR,do_tar,recurse);
  772.       strcpy(cur_dir,saved_curdir);
  773.       free(inbuf);free(outbuf);
  774.     }
  775.   else
  776.     {
  777.       strcpy(rname,cur_dir);
  778.       strcat(rname,finfo->name);
  779.       do_atar(rname,finfo->name,finfo);
  780.     }
  781. }
  782.  
  783. /*
  784.  *
  785.  * restore specific functions
  786.  *
  787.  */
  788.  
  789. static long readtarheader(union hblock *hb, file_info *finfo, char *prefix)
  790. {
  791.   long chk, fchk;
  792.   int i;
  793.   char *jp;
  794.  
  795.   /*
  796.    * read in a "standard" tar format header - we're not that interested
  797.    * in that many fields, though
  798.    */
  799.  
  800.   /* check the checksum */
  801.   for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;) chk+=(0xFF & *jp++);
  802.  
  803.   if (chk == 0)
  804.     return chk;
  805.  
  806.   /* compensate for blanks in chksum header */
  807.   for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
  808.     chk-=(0xFF & *jp++);
  809.  
  810.   chk += ' ' * sizeof(hb->dbuf.chksum);
  811.  
  812.   fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
  813.  
  814.   DEBUG(5, ("checksum totals chk=%d fchk=%d chksum=%s\n",
  815.         chk, fchk, hb->dbuf.chksum));
  816.  
  817.   if (fchk != chk)
  818.     {
  819.       DEBUG(0, ("checksums don't match %d %d\n", fchk, chk));
  820.       return -1;
  821.     }
  822.  
  823.   strcpy(finfo->name, prefix);
  824.  
  825.   /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
  826.   unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
  827.            strlen(hb->dbuf.name) + 1);
  828.  
  829. /* can't handle links at present */
  830.   if (hb->dbuf.linkflag != '0') {
  831.     if (hb->dbuf.linkflag == 0) {
  832.       DEBUG(4, ("Warning: NULL link detected %s\n", finfo->name));
  833.     } else { 
  834.       DEBUG(0, ("this tar file appears to contain some kind of link - ignoring\n"));
  835.       return -2;
  836.     }
  837.   }
  838.     
  839.   if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR)
  840.     || (*(finfo->name+strlen(finfo->name)-1) == '\\'))
  841.     {
  842.       finfo->mode=aDIR;
  843.     }
  844.   else
  845.     finfo->mode=0; /* we don't care about mode at the moment, we'll
  846.             * just make it a regular file */
  847.   /*
  848.    * Bug fix by richard@sj.co.uk
  849.    *
  850.    * REC: restore times correctly (as does tar)
  851.    * We only get the modification time of the file; set the creation time
  852.    * from the mod. time, and the access time to current time
  853.    */
  854.   finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
  855.   finfo->atime = time(NULL);
  856.   finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
  857.  
  858.   return True;
  859. }
  860.  
  861. static void unfixtarname(char *tptr, char *fp, int l)
  862. {
  863.   /* remove '.' from start of file name, convert from unix /'s to
  864.    * dos \'s in path. Kill any absolute path names.
  865.    */
  866.  
  867.   if (*fp == '.') fp++;
  868.   if (*fp == '\\' || *fp == '/') fp++;
  869.  
  870. #ifdef KANJI
  871.   while (l > 0) {
  872.     if (is_shift_jis (*fp)) {
  873.       *tptr++ = *fp++;
  874.       *tptr++ = *fp++;
  875.       l -= 2;
  876.     } else if (is_kana (*fp)) {
  877.       *tptr++ = *fp++;
  878.       l--;
  879.     } else if (*fp == '/') {
  880.       *tptr++ = '\\';
  881.       fp++;
  882.       l--;
  883.     } else {
  884.       *tptr++ = *fp++;
  885.       l--;
  886.     }
  887.   }
  888. #else
  889.   while (l--) { *tptr=(*fp == '/') ? '\\' : *fp; tptr++; fp++; }
  890. #endif
  891. }
  892.  
  893. static long unoct(char *p, int ndgs)
  894. {
  895.   long value=0;
  896.   /* Converts octal string to long, ignoring any non-digit */
  897.  
  898.   while (--ndgs)
  899.     {
  900.       if (isdigit(*p))
  901.         value = (value << 3) | (long) (*p - '0');
  902.  
  903.       p++;
  904.     }
  905.  
  906.   return value;
  907. }
  908.  
  909. static BOOL smbcreat(file_info finfo, int *fnum, char *inbuf, char *outbuf)
  910. {
  911.   char *p;
  912.   /* *must* be called with buffer ready malloc'ed */
  913.   /* open remote file */
  914.   
  915.   memset(outbuf,0,smb_size);
  916.   set_message(outbuf,3,2 + strlen(finfo.name),True);
  917.   CVAL(outbuf,smb_com) = SMBcreate;
  918.   SSVAL(outbuf,smb_tid,cnum);
  919.   setup_pkt(outbuf);
  920.   
  921.   SSVAL(outbuf,smb_vwv0,finfo.mode);
  922.   put_dos_date3(outbuf,smb_vwv1,finfo.mtime);
  923.   
  924.   p = smb_buf(outbuf);
  925.   *p++ = 4;      
  926.   strcpy(p,finfo.name);
  927.   
  928.   send_smb(Client,outbuf);
  929.   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
  930.   
  931.   if (CVAL(inbuf,smb_rcls) != 0)
  932.     {
  933.       DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),
  934.            finfo.name));
  935.       return 0;
  936.     }
  937.   
  938.   *fnum = SVAL(inbuf,smb_vwv0);
  939.   return True;
  940. }
  941.  
  942.  
  943. static BOOL smbwrite(int fnum, int n, int low, int high, int left,
  944.              char *bufferp, char *inbuf, char *outbuf)
  945. {
  946.   /* *must* be called with buffer ready malloc'ed */
  947.  
  948.   memset(outbuf,0,smb_size);
  949.   set_message(outbuf,5,n + 3,True);
  950.   
  951.   memcpy(smb_buf(outbuf)+3, bufferp, n);
  952.   
  953.   set_message(outbuf,5,n + 3, False);
  954.   CVAL(outbuf,smb_com) = SMBwrite;
  955.   SSVAL(outbuf,smb_tid,cnum);
  956.   setup_pkt(outbuf);
  957.   
  958.   SSVAL(outbuf,smb_vwv0,fnum);
  959.   SSVAL(outbuf,smb_vwv1,n);
  960.   SIVAL(outbuf,smb_vwv2,low);
  961.   SSVAL(outbuf,smb_vwv4,left);
  962.   CVAL(smb_buf(outbuf),0) = 1;
  963.   SSVAL(smb_buf(outbuf),1,n);
  964.  
  965.   send_smb(Client,outbuf); 
  966.   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
  967.   
  968.   if (CVAL(inbuf,smb_rcls) != 0)
  969.     {
  970.       DEBUG(0,("%s writing remote file\n",smb_errstr(inbuf)));
  971.       return False;
  972.     }
  973.   
  974.   if (n != SVAL(inbuf,smb_vwv0))
  975.     {
  976.       DEBUG(0,("Error: only wrote %d bytes out of %d\n",
  977.            SVAL(inbuf,smb_vwv0), n));
  978.       return False;
  979.     }
  980.  
  981.   return True;
  982. }
  983.  
  984. static BOOL smbshut(file_info finfo, int fnum, char *inbuf, char *outbuf)
  985. {
  986.   /* *must* be called with buffer ready malloc'ed */
  987.  
  988.   memset(outbuf,0,smb_size);
  989.   set_message(outbuf,3,0,True);
  990.   CVAL(outbuf,smb_com) = SMBclose;
  991.   SSVAL(outbuf,smb_tid,cnum);
  992.   setup_pkt(outbuf);
  993.   
  994.   SSVAL(outbuf,smb_vwv0,fnum);
  995.   put_dos_date3(outbuf,smb_vwv1,finfo.mtime);
  996.   
  997.   DEBUG(3,("Setting date to %s (0x%X)",
  998.        asctime(LocalTime(&finfo.mtime,GMT_TO_LOCAL)),
  999.        finfo.mtime));
  1000.   
  1001.   send_smb(Client,outbuf);
  1002.   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
  1003.   
  1004.   if (CVAL(inbuf,smb_rcls) != 0)
  1005.     {
  1006.       DEBUG(0,("%s closing remote file %s\n",smb_errstr(inbuf),
  1007.            finfo.name));
  1008.       return False;
  1009.     }
  1010.  
  1011.   return True;
  1012. }
  1013.  
  1014.  
  1015. static BOOL smbchkpath(char *fname, char *inbuf, char *outbuf)
  1016. {
  1017.   char *p;
  1018.  
  1019.   memset(outbuf,0,smb_size);
  1020.   set_message(outbuf,0,4 + strlen(fname),True);
  1021.   CVAL(outbuf,smb_com) = SMBchkpth;
  1022.   SSVAL(outbuf,smb_tid,cnum);
  1023.   setup_pkt(outbuf);
  1024.  
  1025.   p = smb_buf(outbuf);
  1026.   *p++ = 4;
  1027.   strcpy(p,fname);
  1028.  
  1029.   send_smb(Client,outbuf);
  1030.   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
  1031.  
  1032.   DEBUG(5,("smbchkpath: %s\n",smb_errstr(inbuf)));
  1033.  
  1034.   return(CVAL(inbuf,smb_rcls) == 0);
  1035. }
  1036.  
  1037.  
  1038. static BOOL smbmkdir(char *fname, char *inbuf, char *outbuf)
  1039. {
  1040.   /* *must* be called with buffer ready malloc'ed */
  1041.   char *p;
  1042.  
  1043.   memset(outbuf,0,smb_size);
  1044.   set_message(outbuf,0,2 + strlen(fname),True);
  1045.   
  1046.   CVAL(outbuf,smb_com) = SMBmkdir;
  1047.   SSVAL(outbuf,smb_tid,cnum);
  1048.   setup_pkt(outbuf);
  1049.   
  1050.   p = smb_buf(outbuf);
  1051.   *p++ = 4;      
  1052.   strcpy(p,fname);
  1053.   
  1054.   send_smb(Client,outbuf);
  1055.   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
  1056.   
  1057.   if (CVAL(inbuf,smb_rcls) != 0)
  1058.     {
  1059.       DEBUG(0,("%s making remote directory %s\n",
  1060.            smb_errstr(inbuf),fname));
  1061.       return(False);
  1062.     }
  1063.  
  1064.   return(True);
  1065. }
  1066.  
  1067. static BOOL ensurepath(char *fname, char *inbuf, char *outbuf)
  1068. {
  1069.   /* *must* be called with buffer ready malloc'ed */
  1070.   /* ensures path exists */
  1071.  
  1072.   pstring partpath, ffname;
  1073.   char *p=fname, *basehack;
  1074.  
  1075.   *partpath = 0;
  1076.  
  1077.   /* fname copied to ffname so can strtok */
  1078.  
  1079.   strcpy(ffname, fname);
  1080.  
  1081.   /* do a `basename' on ffname, so don't try and make file name directory */
  1082.   if ((basehack=strrchr(ffname, '\\')) == NULL)
  1083.     return True;
  1084.   else
  1085.     *basehack='\0';
  1086.  
  1087.   p=strtok(ffname, "\\");
  1088.  
  1089.   while (p)
  1090.     {
  1091.       strcat(partpath, p);
  1092.  
  1093.       if (!smbchkpath(partpath, inbuf, outbuf)) {
  1094.     if (!smbmkdir(partpath, inbuf, outbuf))
  1095.       {
  1096.         DEBUG(0, ("Error mkdirhiering\n"));
  1097.         return False;
  1098.       }
  1099.     else
  1100.       DEBUG(3, ("mkdirhiering %s\n", partpath));
  1101.  
  1102.       }
  1103.  
  1104.       strcat(partpath, "\\");
  1105.       p = strtok(NULL,"/\\");
  1106.     }
  1107.  
  1108.     return True;
  1109. }
  1110.  
  1111. static void do_tarput()
  1112. {
  1113.   file_info finfo;
  1114.   int nread=0, bufread;
  1115.   char *inbuf,*outbuf; 
  1116.   int fsize=0;
  1117.   
  1118.   struct timeval tp_start;
  1119.   GetTimeOfDay(&tp_start);
  1120.   
  1121.   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
  1122.   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
  1123.   
  1124.   if (!inbuf || !outbuf)
  1125.     {
  1126.       DEBUG(0,("out of memory\n"));
  1127.       return;
  1128.     }
  1129.   
  1130.   /*
  1131.    * Must read in tbufsiz dollops
  1132.    * - this is crude as should detect
  1133.    */
  1134.   
  1135.   while ((bufread=read(tarhandle, tarbuf, tbufsiz))) {
  1136.     char *bufferp, *endofbuffer;
  1137.     int chunk, fnum;
  1138.     
  1139.     bufferp=tarbuf; 
  1140.     endofbuffer=tarbuf+bufread;
  1141.     
  1142.     do {
  1143.       if (!fsize)
  1144.     {
  1145.       switch (readtarheader((union hblock *) bufferp, &finfo, cur_dir))
  1146.         {
  1147.         case -2:             /* something dodgy but not fatal about this */
  1148.           DEBUG(0, ("skipping %s...\n", finfo.name));
  1149.           bufferp+=TBLOCK;   /* header - like a link */
  1150.           continue;
  1151.         case -1:
  1152.           DEBUG(0, ("abandoning restore\n"));
  1153.           free(inbuf); free(outbuf);
  1154.           return;
  1155.         case 0: /* chksum is zero - we assume that one all zero
  1156.              *header block will do for eof */
  1157.           DEBUG(0,
  1158.             ("total of %d tar files restored to share\n", ntarf));
  1159.           free(inbuf); free(outbuf);
  1160.           return;
  1161.         default:
  1162.           break;
  1163.         }
  1164.  
  1165.       if (finfo.mode & aDIR)
  1166.         {
  1167.           if (!smbchkpath(finfo.name, inbuf, outbuf)
  1168.           && !smbmkdir(finfo.name, inbuf, outbuf))
  1169.         {
  1170.           DEBUG(0, ("abandoning restore\n"));
  1171.           free(inbuf); free(outbuf);
  1172.           return;
  1173.           }
  1174.           else
  1175.         {
  1176.           bufferp+=TBLOCK;
  1177.           continue;
  1178.         }
  1179.         }
  1180.       
  1181.       fsize=finfo.size;
  1182.  
  1183.       if (ensurepath(finfo.name, inbuf, outbuf)
  1184.           && !smbcreat(finfo, &fnum, inbuf, outbuf))
  1185.         {
  1186.           DEBUG(0, ("abandoning restore\n"));
  1187.           free(inbuf);free(outbuf);
  1188.           return;
  1189.         }
  1190.       
  1191.       DEBUG(0,("restore tar file %s of size %d bytes\n",
  1192.            finfo.name,finfo.size));
  1193.  
  1194.       nread=0;
  1195.       if ((bufferp+=TBLOCK) >= endofbuffer) break;      
  1196.     } /* if nread */
  1197.     
  1198.       /* write out the file in chunk sized chunks - don't
  1199.        * go past end of buffer though */
  1200.       chunk=(fsize-nread < endofbuffer - bufferp)
  1201.     ? fsize - nread : endofbuffer - bufferp;
  1202.       
  1203.       while (chunk > 0) {
  1204.     int minichunk=MIN(chunk, max_xmit-200);
  1205.     
  1206.     if (!smbwrite(fnum, /* file descriptor */
  1207.               minichunk, /* n */
  1208.               nread, /* offset low */
  1209.               0, /* offset high - not implemented */
  1210.               fsize-nread, /* left - only hint to server */
  1211.               bufferp,
  1212.               inbuf,
  1213.               outbuf))
  1214.       {
  1215.         DEBUG(0, ("Error writing remote file\n"));
  1216.         free(inbuf); free(outbuf);
  1217.         return;
  1218.       }
  1219.     DEBUG(5, ("chunk writing fname=%s fnum=%d nread=%d minichunk=%d chunk=%d size=%d\n", finfo.name, fnum, nread, minichunk, chunk, fsize));
  1220.     
  1221.     bufferp+=minichunk; nread+=minichunk;
  1222.     chunk-=minichunk;
  1223.       }
  1224.       
  1225.       if (nread>=fsize)
  1226.     {
  1227.       if (!smbshut(finfo, fnum, inbuf, outbuf))
  1228.         {
  1229.           DEBUG(0, ("Error closing remote file\n"));
  1230.           free(inbuf);free(outbuf);
  1231.           return;
  1232.         }
  1233.       if (fsize % TBLOCK) bufferp+=TBLOCK - (fsize % TBLOCK);
  1234.       DEBUG(5, ("bufferp is now %d (psn=%d)\n",
  1235.             (long) bufferp, (long)(bufferp - tarbuf)));
  1236.       ntarf++;
  1237.       fsize=0;
  1238.     }
  1239.     } while (bufferp < endofbuffer);
  1240.   }
  1241.   if (ntarf) 
  1242.     DEBUG(0, ("premature eof on tar file ?\n"));
  1243.   else
  1244.     DEBUG(0,("total of %d tar files restored to share\n", ntarf));
  1245.   
  1246.   free(inbuf); free(outbuf);
  1247. }
  1248.  
  1249. /*
  1250.  * samba commands
  1251.  */
  1252.  
  1253. /* blocksize command */
  1254.  
  1255. void cmd_block(void)
  1256. {
  1257.   fstring buf;
  1258.   int block;
  1259.  
  1260.   if (!next_token(NULL,buf,NULL))
  1261.     {
  1262.       DEBUG(0, ("blocksize <n>\n"));
  1263.       return;
  1264.     }
  1265.  
  1266.   block=atoi(buf);
  1267.   if (block < 0 || block > 65535)
  1268.     {
  1269.       DEBUG(0, ("blocksize out of range"));
  1270.       return;
  1271.     }
  1272.  
  1273.   blocksize=block;
  1274.   DEBUG(2,("blocksize is now %d\n", blocksize));
  1275. }
  1276.  
  1277. void cmd_tarmode(void)
  1278. {
  1279.   fstring buf;
  1280.  
  1281.   while (next_token(NULL,buf,NULL)) {
  1282.     if (strequal(buf, "full"))
  1283.       tar_inc=False;
  1284.     else if (strequal(buf, "inc"))
  1285.       tar_inc=True;
  1286.     else if (strequal(buf, "reset"))
  1287.       tar_reset=True;
  1288.     else if (strequal(buf, "noreset"))
  1289.       tar_reset=False;
  1290.     else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
  1291.   }
  1292.  
  1293.   DEBUG(0, ("tarmode is now %s, %s\n",
  1294.         tar_inc ? "incremental" : "full",
  1295.         tar_reset ? "reset" : "noreset"));
  1296. }
  1297.  
  1298. /* freebie crude attrib command */
  1299.  
  1300. void cmd_setmode(void)
  1301. {
  1302.   char *q;
  1303.   fstring buf;
  1304.   pstring fname;
  1305.   int attra[2];
  1306.   int direct=1;
  1307.  
  1308.   attra[0] = attra[1] = 0;
  1309.  
  1310.   if (!next_token(NULL,buf,NULL))
  1311.     {
  1312.       DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
  1313.       return;
  1314.     }
  1315.  
  1316.   strcpy(fname, cur_dir);
  1317.   strcat(fname, buf);
  1318.  
  1319.   while (next_token(NULL,buf,NULL)) {
  1320.     q=buf;
  1321.  
  1322.     while(*q)
  1323.       switch (*q++) {
  1324.       case '+': direct=1;
  1325.     break;
  1326.       case '-': direct=0;
  1327.     break;
  1328.       case 'r': attra[direct]|=aRONLY;
  1329.     break;
  1330.       case 'h': attra[direct]|=aHIDDEN;
  1331.     break;
  1332.       case 's': attra[direct]|=aSYSTEM;
  1333.     break;
  1334.       case 'a': attra[direct]|=aARCH;
  1335.     break;
  1336.       default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
  1337.     return;
  1338.       }
  1339.   }
  1340.  
  1341.   if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
  1342.     {
  1343.       DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
  1344.       return;
  1345.     }
  1346.  
  1347. DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
  1348.   (void) do_setrattr(fname, attra[ATTRSET], ATTRSET);
  1349.   (void) do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
  1350. }
  1351.  
  1352. /*
  1353.  * do a tar command
  1354.  */
  1355.  
  1356. void cmd_tar(char *inbuf, char *outbuf)
  1357. {
  1358.   int attribute = aDIR | aSYSTEM | aHIDDEN;
  1359.   pstring ffname, tarmac;
  1360.   fstring buf;
  1361.   char *p = buf;
  1362.  
  1363.   if (!next_token(NULL,buf,NULL))
  1364.     {
  1365.       DEBUG(0,("tar [c|x] <filename>\n"));
  1366.       return;
  1367.     }
  1368.  
  1369.   if (*p == 'c') {
  1370.     if (!next_token(NULL,buf,NULL))
  1371.       {
  1372.     DEBUG(0,("tar [c|x] <filename> [<tar mask>]\n"));
  1373.     return;
  1374.       }
  1375.     
  1376.     strcpy(ffname,p);
  1377.     
  1378.     if(!strcmp(ffname,"-"))
  1379.       tarhandle = fileno(stdout);
  1380.     else 
  1381.       tarhandle = creat(ffname,0644);
  1382.     
  1383.     if (tarhandle < 0)
  1384.       {
  1385.     DEBUG(0,("Error opening local file %s\n",ffname));
  1386.     return;
  1387.       }
  1388.     
  1389.     initarbuf();
  1390.  
  1391.     strcpy(tarmac,cur_dir);
  1392.     if (next_token(NULL,buf,NULL))
  1393.       do {
  1394.     if(tarmac[strlen(tarmac)-1]!='\\')
  1395.       strcat(tarmac,"\\");
  1396.     
  1397.     if (*p == '\\')
  1398.       strcpy(tarmac,p);
  1399.     else
  1400.       strcat(tarmac,p);
  1401.       } while (next_token(NULL,buf,NULL));
  1402.     else
  1403.       strcat(tarmac,"*.*");
  1404.     
  1405.     do_dir((char *)inbuf,(char *)outbuf,tarmac,attribute,do_tar,recurse);
  1406.     
  1407.     if (ntarf) dotareof(tarhandle);
  1408.     close(tarhandle);
  1409.     free(tarbuf);
  1410.     
  1411.     DEBUG(0, ("tar: dumped %d tar files\n", ntarf));
  1412.   }
  1413.   else if (*p=='x') {
  1414.     if (!next_token(NULL,buf,NULL))
  1415.       {
  1416.     DEBUG(0,("tar [c|x] <filename> [<tar mask>]\n"));
  1417.     return;
  1418.       }
  1419.     
  1420.     strcpy(ffname,p);
  1421.     
  1422.     if(!strcmp(ffname,"-"))
  1423.       tarhandle = fileno(stdin);
  1424.     else 
  1425.       if ((tarhandle = open(ffname,O_RDONLY)) == -1)
  1426.     {
  1427.       DEBUG(0,("Error opening local file %s\n",ffname));
  1428.       return;
  1429.     }
  1430.  
  1431.     initarbuf();
  1432.  
  1433.     do_tarput();
  1434.  
  1435.     free(tarbuf);
  1436.     close(tarhandle);
  1437.   }
  1438.   else
  1439.     DEBUG(0,("tar [c|x] <filename>\n"));
  1440. }
  1441.  
  1442.